// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包反射实现运行时反射，允许程序操作具有任意类型的对象。典型的用法是使用静态类型接口{}获取一个值
// 并通过调用返回类型的
// 来提取其动态类型信息。
// 
// 对ValueOf的调用返回一个表示运行时数据的值。
// Zero接受一个类型并返回一个表示该类型的零值的值
// 。
// 
// 有关围棋中反射的介绍，请参见“反射定律”：
// https:
package reflect

import (
	"internal/goarch"
	"internal/unsafeheader"
	"strconv"
	"sync"
	"unicode"
	"unicode/utf8"
	"unsafe"
)

// Type是Go类型的表示形式。
// 
// 并非所有方法都适用于所有类型。每种方法的文档中都注明了限制条件
// 如果有。
// 在调用特定于种类的方法之前，使用Kind方法找出类型的种类。调用不适合该类型的方法
// 会导致运行时恐慌。
// 
// 类型值是可比较的，例如使用==运算符，
// 因此它们可以用作映射键。
// 如果两个类型值代表相同的类型，则它们是相等的。
type Type interface {
	// 适用于所有类型的方法。

	// Align在内存中分配时，返回
	// 此类型值的字节对齐方式。
	Align() int

	// FieldAlign返回
	// 此类型的值在用作结构中的字段时的对齐方式（以字节为单位）。
	FieldAlign() int

	// 方法返回类型的方法集中的第i个方法。
	// 如果我不在[0，NumMethod（）范围内，它会感到恐慌).
	// 
	// 对于非接口类型T或*T，返回方法的类型和函数
	// 字段描述的函数的第一个参数是接收方
	// 并且只有导出的方法才可访问。
	// 
	// 对于接口类型，返回的方法的type字段给出了
	// 方法签名，没有接收者，Func字段为零。
	// 
	// 方法按字典顺序排序。
	Method(int) Method

	// MethodByName返回在类型的
	// 方法集中具有该名称的方法，并返回一个布尔值，指示是否找到该方法。
	// 
	// 对于非接口类型T或*T，返回方法的类型和Func 
	// 字段描述的函数的第一个参数是接收方。
	// 
	// 对于接口类型，返回的方法的type字段给出了
	// 方法签名，没有接收者，Func字段为零。
	MethodByName(string) (Method, bool)

	// NumMethod返回使用Method可访问的方法数。
	// 
	// 注意，NumMethod只对接口类型统计未报告的方法。
	NumMethod() int

	// Name返回定义类型的包中的类型名称。
	// 对于其他（未定义）类型，它返回空字符串。
	Name() string

	// PkgPath返回定义类型的包路径，即唯一标识包的导入路径
	// ，例如“encoding/base64”。
	// 如果类型是预先声明的（字符串，错误）或未定义（*T，struct{}，
	// /[]int，或者A是未定义类型的别名，则包路径
	// 将是空字符串。
	PkgPath() string

	// Size返回存储给定类型的值所需的字节数；这类似于不安全。Sizeof。
	Size() uintptr

	// String返回该类型的字符串表示形式。
	// 字符串表示法可能使用缩短的包名
	// （例如，base64而不是“encoding/base64”），并且不能保证
	// 在类型中是唯一的。要测试类型标识，请直接比较类型。
	String() string

	// Kind返回此类型的特定种类。
	Kind() Kind

	// Implements报告该类型是否实现了接口类型u。
	Implements(u Type) bool

	// AssignableTo报告该类型的值是否可分配给类型u。
	AssignableTo(u Type) bool

	// ConvertibleTo报告该类型的值是否可转换为类型u。
	// ConvertibleTo即使返回true，转换仍可能会死机。
	// 例如，[]T类型的片可以转换为*[N]T，
	// 但如果其长度小于N，转换将崩溃。
	ConvertibleTo(u Type) bool

	// Compariable报告此类型的值是否可比。
	// 即使可比回报率为真，这种比较仍然可能令人恐慌。
	// 例如，接口类型的值是可比较的，
	// 但是如果它们的动态类型不可比较，比较就会出现恐慌。
	Comparable() bool

	// 方法仅适用于某些类型，具体取决于种类。
	// 每种允许的方法是：
	// 
	// Int*、Uint*、Float*、Complex*：Bits 
	// 数组：Elem、Len 
	// Chan:ChanDir、Elem 
	// 函数：In、NumIn、Out、NumOut、IsVariadic。
	// Map:Key，Elem 
	// 指针：Elem 
	// 切片：Elem 
	// 结构：Field，FieldByIndex，FieldByName，fieldbynamefnc，NumField 

	// 位返回类型的大小（以位为单位）。
	// 如果类型的种类不是
	// 大小或未大小的Int、Uint、Float或Complex种类之一，则会导致恐慌。
	Bits() int

	// ChanDir返回通道类型的方向。
	// 如果类型不是Chan，它会感到恐慌。
	ChanDir() ChanDir

	// IsVariatic报告函数类型的最终输入参数
	// 是否为“…”参数如果是，t.In（t.NumIn（）-1）返回参数的
	// 隐式实际类型[]t.
	// 
	// 对于具体性，如果t表示func（x int，y…float64），则
	// 
	// t.NumIn（）==2 
	// t.In（0）是反映。“int”
	// t.In（1）的类型为反射。“[]float64”
	// t.IsVariadic（）==true 
	// 
	// IsVariadic panics，如果类型的种类不是Func。
	IsVariadic() bool

	// Elem返回类型的元素类型。
	// 如果类型的种类不是数组、Chan、Map、指针或切片，则会导致恐慌。
	Elem() Type

	// 字段返回结构类型的第i个字段。
	// 如果类型的种类不是Struct，它就会恐慌。
	// 如果我不在[0，NumField（）范围内，它会惊慌失措).
	Field(i int) StructField

	// FieldByIndex将对应于
	// 的嵌套字段返回给索引序列。它相当于为每个索引i依次调用字段
	// 
	// 如果类型的种类不是Struct，它就会崩溃。
	FieldByIndex(index []int) StructField

	// FieldByName返回具有给定名称
	// 的结构字段，并返回一个布尔值，指示是否找到该字段。
	FieldByName(name string) (StructField, bool)

	// FieldByNameFunc返回结构字段，其名称为
	// 满足匹配函数，布尔值指示是否找到该字段。
	// 
	// FieldByNameFunc考虑结构本身中的字段
	// 然后考虑任何嵌入结构中的字段，按照广度优先顺序，
	// 停止在最浅的嵌套深度，其中包含一个或多个满足匹配函数的
	// 字段。如果该深度的多个字段
	// 满足匹配函数，则它们会相互取消
	// 并且FieldByNameFunc不返回匹配。
	// 此行为反映了Go在包含嵌入字段的结构中对名称查找的处理。
	FieldByNameFunc(match func(string) bool) (StructField, bool)

	// In返回函数类型的第i个输入参数的类型。
	// 如果类型的种类不正常，它会惊慌失措。
	// 如果我不在[0，NumIn（）范围内，它会惊慌失措).
	In(i int) Type

	// Key返回映射类型的键类型。
	// 如果类型不是Map，它会恐慌。
	Key() Type

	// Len返回数组类型的长度。
	// 如果类型的种类不是数组，它会恐慌。
	Len() int

	// NumField返回结构类型的字段计数。
	// 如果类型的种类不是Struct，它就会恐慌。
	NumField() int

	// NumIn返回函数类型的输入参数计数。
	// 如果类型的种类不是Func，它会感到恐慌。
	NumIn() int

	// NumOut返回函数类型的输出参数计数。
	// 如果类型的种类不是Func，它会惊慌失措。
	NumOut() int

	// Out返回函数类型的第i个输出参数的类型。
	// 如果类型的种类不是Func，它会惊慌失措。ABCFDG＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊。
	Out(i int) Type

	common() *rtype
	uncommon() *uncommonType
}

// 如果结构类型t包含
// 多个名为x的字段（从不同的包嵌入），则t.FieldByName（“x”）的定义不明确。
// FieldByName可能返回一个名为x的字段，或者可能报告没有字段。
// 参见https:

/*
 * These data structures are known to the compiler (../cmd/compile/internal/reflectdata/reflect.go).
 * A few are known to ../runtime/type.go to convey to debuggers.
 * They are also known to ../runtime/type.go.
 */

// A Kind表示类型所代表的特定类型。
// 零类型不是有效类型。
type Kind uint

const (
	Invalid Kind = iota
	Bool
	Int
	Int8
	Int16
	Int32
	Int64
	Uint
	Uint8
	Uint16
	Uint32
	Uint64
	Uintptr
	Float32
	Float64
	Complex64
	Complex128
	Array
	Chan
	Func
	Interface
	Map
	Pointer
	Slice
	String
	Struct
	UnsafePointer
)

// Ptr是指针类的旧名称。
const Ptr = Pointer

// tflag被一个rtype用来表示在rtype值后面的内存中有哪些额外的类型信息。
// 
// tflag值必须与以下文件中的副本保持同步：
// cmd/compile/internal/reflectdata/reflect。转到
// cmd/link/internal/ld/decodesym。转到
// runtime/type。go 
type tflag uint8

const (
	// tflagUngeneral意味着在外部类型结构之外有一个指针*uncoMonType，
	// 。
	// 
	// 例如，如果t.Kind（）==Struct和t.tflag&tflag！=0，
	// t有uncommonType数据，可以访问为：
	// 
	// type tuncomon struct{
	// structType 
	// u uncommonType 
	// }
	// u:=（-tuncomon）（unsafe.Pointer（t））。u 
	tflagUncommon tflag = 1 << 0

	// tflagExtraStar表示str字段中的名称有一个
	// extronous'*'前缀。这是因为对于
	// 程序中的大多数类型T，类型*T也存在，并且重复使用str数据
	// 可以节省二进制大小。
	tflagExtraStar tflag = 1 << 1

	// tflagNamed表示该类型有一个名称。
	tflagNamed tflag = 1 << 2

	// tflagRegularMemory意味着equal和hash函数可以将
	// 此类型视为一个t.size字节的单个区域。
	tflagRegularMemory tflag = 1 << 3
)

// rtype是大多数值的常见实现。
// 嵌入到其他结构类型中。
// 
// rtype必须与保持同步/运行时/类型。开始：/^键入_类型
type rtype struct {
	size       uintptr
	ptrdata    uintptr // 类型中可以包含指针的字节数
	hash       uint32  // 类型的哈希；避免哈希表中的计算
	tflag      tflag   // 额外类型信息标志
	align      uint8   // 将变量与此类型对齐
	fieldAlign uint8   // 将结构字段与此类型对齐
	kind       uint8   // 枚举C 
	// 用于比较此类型对象的函数
	equal     func(unsafe.Pointer, unsafe.Pointer) bool
	gcdata    *byte   // 垃圾收集数据
	str       nameOff // 字符串形式
	ptrToThis typeOff // 指向此类型的指针的类型，可能是零
}

// 非接口类型上的方法
type method struct {
	name nameOff // 方法名称
	mtyp typeOff // 方法类型（不带接收器）
	ifn  textOff // 在接口调用中使用的fn（单字接收器）
	tfn  textOff // 用于常规方法调用的fn 
}

// 仅对定义的类型或具有方法
// （如果T是已定义的类型，则T和*T的uncommonTypes具有方法）。
// 使用指向此结构的指针可减少描述未定义类型（无方法）所需的总体大小。
type uncommonType struct {
	pkgPath nameOff // 导入路径；内置类型如int、string 
	mcount  uint16  // 方法数
	xcount  uint16  // 导出方法数
	moff    uint32  // 从这个uncommontype到[mcount]方法的偏移量
	_       uint32  // 未使用的
}

// ChanDir表示通道类型的方向。
type ChanDir int

const (
	RecvDir ChanDir             = 1 << iota // <-chan 
	SendDir                                 // chan<-
	BothDir = RecvDir | SendDir             // chan 
)

// arrayType表示固定的数组类型。
type arrayType struct {
	rtype
	elem  *rtype // 数组元素类型
	slice *rtype // 切片类型
	len   uintptr
}

// chanType表示通道类型。
type chanType struct {
	rtype
	elem *rtype  // 通道元素类型
	dir  uintptr // 通道方向（ChanDir）
}

// funcType表示函数类型。
// 
// A*rtype为每个in和out参数存储在一个数组中，
// 直接跟随funcType（可能还有它的UncoMonType）。所以
// 一个方法、一个输入、一个输出的函数类型是：
// 
// struct{
// funcType 
// unomonType 
// /[2]*rtype/[0]在[1]在外
// /}
type funcType struct {
	rtype
	inCount  uint16
}

// imethod表示接口类型
type imethod struct {
	name nameOff // 方法名称
	typ  typeOff // 。
}

// interfaceType下面的（*FuncType）表示接口类型。
type interfaceType struct {
	rtype
	pkgPath name      // 导入路径
	methods []imethod // 按哈希
}

// mapType表示映射类型。
type mapType struct {
	rtype
	key    *rtype // 映射键类型
	elem   *rtype // 映射元素（值）类型
	bucket *rtype // 内部bucket结构
	// 散列键函数（ptr到键，种子）->散列
	hasher     func(unsafe.Pointer, uintptr) uintptr
	keysize    uint8  // 键槽大小
	valuesize  uint8  // 值槽大小
	bucketsize uint16 // bucket大小
	flags      uint32
}

// ptrType表示指针类型。
type ptrType struct {
	rtype
	elem *rtype // 指针元素（指向）类型
}

// 切片类型表示切片类型。
type sliceType struct {
	rtype
	elem *rtype // 切片元素类型
}

// 结构字段
type structField struct {
	name        name    // 名称始终为非空
	typ         *rtype  // 字段类型
	offsetEmbed uintptr // 字段的字节偏移量<1 |已嵌入
}

func (f *structField) offset() uintptr {
	return f.offsetEmbed >> 1
}

func (f *structField) embedded() bool {
	return f.offsetEmbed&1 != 0
}

// structType表示结构类型。
type structType struct {
	rtype
	pkgPath name
	fields  []structField // 按偏移量排序
}

// 名称是一个带有可选额外数据的编码类型名称。
// 
// 第一个字节是一个位字段，包含：
// 
// 1<<0导出名称
// 1<<1标签数据跟在名称后面
// 1<<2 pkgPath nameOff跟在名称后面，标签
// 后跟名称本身。
// 
// 如果存在标记数据，它还有一个不同的编码长度
// 后跟标记本身。
// 
// 如果导入路径如下，则在
// 末尾的4个字节将形成一个名称。导入路径仅为具体的
// 方法设置，这些方法定义在与其类型不同的包中。
// 
// 如果名称以“*”开头，则导出的位表示
// 是否导出指向的类型。
// 
// 注意：此编码必须在此处和中匹配：
// cmd/compile/internal/reflectdata/reflect。转到
// 运行时/类型。转到
// internal/reflectlite/type。转到
// cmd/link/internal/ld/decodesym。go 

type name struct {
	bytes *byte
}

func (n name) data(off int, whySafe string) *byte {
	return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off), whySafe))
}

func (n name) isExported() bool {
	return (*n.bytes)&(1<<0) != 0
}

func (n name) hasTag() bool {
	return (*n.bytes)&(1<<1) != 0
}

// readVarint按编码/二进制编码方式解析变量。
// 返回编码字节数和编码值。
func (n name) readVarint(off int) (int, int) {
	v := 0
	for i := 0; ; i++ {
		x := *n.data(off+i, "read varint")
		v += int(x&0x7f) << (7 * i)
		if x&0x80 == 0 {
			return i + 1, v
		}
	}
}

// WritePrint以各种形式将n写入buf。返回
// 写入的字节数。n必须是非负的。
// 最多写入10个字节。
func writeVarint(buf []byte, n int) int {
	for i := 0; ; i++ {
		b := byte(n & 0x7f)
		n >>= 7
		if n == 0 {
			buf[i] = b
			return i + 1
		}
		buf[i] = b | 0x80
	}
}

func (n name) name() (s string) {
	if n.bytes == nil {
		return
	}
	i, l := n.readVarint(1)
	hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
	hdr.Data = unsafe.Pointer(n.data(1+i, "non-empty string"))
	hdr.Len = l
	return
}

func (n name) tag() (s string) {
	if !n.hasTag() {
		return ""
	}
	i, l := n.readVarint(1)
	i2, l2 := n.readVarint(1 + i + l)
	hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
	hdr.Data = unsafe.Pointer(n.data(1+i+l+i2, "non-empty string"))
	hdr.Len = l2
	return
}

func (n name) pkgPath() string {
	if n.bytes == nil || *n.data(0, "name flag field")&(1<<2) == 0 {
		return ""
	}
	i, l := n.readVarint(1)
	off := 1 + i + l
	if n.hasTag() {
		i2, l2 := n.readVarint(off)
		off += i2 + l2
	}
	var nameOff int32
	// 注意，这个字段在内存中可能没有对齐，因此我们不能在这里使用直接的int32赋值。
	copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off, "name offset field")))[:])
	pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.bytes), nameOff))}
	return pkgPathName.name()
}

func newName(n, tag string, exported bool) name {
	if len(n) >= 1<<29 {
		panic("reflect.nameFrom: name too long: " + n[:1024] + "...")
	}
	if len(tag) >= 1<<29 {
		panic("reflect.nameFrom: tag too long: " + tag[:1024] + "...")
	}
	var nameLen [10]byte
	var tagLen [10]byte
	nameLenLen := writeVarint(nameLen[:], len(n))
	tagLenLen := writeVarint(tagLen[:], len(tag))

	var bits byte
	l := 1 + nameLenLen + len(n)
	if exported {
		bits |= 1 << 0
	}
	if len(tag) > 0 {
		l += tagLenLen + len(tag)
		bits |= 1 << 1
	}

	b := make([]byte, l)
	b[0] = bits
	copy(b[1:], nameLen[:nameLenLen])
	copy(b[1+nameLenLen:], n)
	if len(tag) > 0 {
		tb := b[1+nameLenLen+len(n):]
		copy(tb, tagLen[:tagLenLen])
		copy(tb[tagLenLen:], tag)
	}

	return name{bytes: &b[0]}
}

/*
 * The compiler knows the exact layout of all the data structures above.
 * The compiler does not know about the data structures and methods below.
 */

// 方法表示一个方法。
type Method struct {
	// Name是方法名。
	Name string

	// PkgPath是限定小写（未报告）
	// 方法名称的包路径。对于大写（导出的）方法名称，它为空。
	// PkgPath和Name的组合唯一标识方法集中的方法
	// 。
	// 请参阅https:
	PkgPath string

	Type  Type  // 方法类型
	Func  Value // func，其中receiver作为第一个参数
	Index int   // 类型的索引。方法
}

// IsExported报告该方法是否已导出。
func (m Method) IsExported() bool {
	return m.PkgPath == ""
}

const (
	kindDirectIface = 1 << 5
	kindGCProg      = 1 << 6 // 类型。gc指向gc程序
	kindMask        = (1 << 5) - 1
)

// String返回k的名称。
func (k Kind) String() string {
	if int(k) < len(kindNames) {
		return kindNames[k]
	}
	return "kind" + strconv.Itoa(int(k))
}

var kindNames = []string{
	Invalid:       "invalid",
	Bool:          "bool",
	Int:           "int",
	Int8:          "int8",
	Int16:         "int16",
	Int32:         "int32",
	Int64:         "int64",
	Uint:          "uint",
	Uint8:         "uint8",
	Uint16:        "uint16",
	Uint32:        "uint32",
	Uint64:        "uint64",
	Uintptr:       "uintptr",
	Float32:       "float32",
	Float64:       "float64",
	Complex64:     "complex64",
	Complex128:    "complex128",
	Array:         "array",
	Chan:          "chan",
	Func:          "func",
	Interface:     "interface",
	Map:           "map",
	Pointer:       "ptr",
	Slice:         "slice",
	String:        "string",
	Struct:        "struct",
	UnsafePointer: "unsafe.Pointer",
}

func (t *uncommonType) methods() []method {
	if t.mcount == 0 {
		return nil
	}
	return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.mcount > 0"))[:t.mcount:t.mcount]
}

func (t *uncommonType) exportedMethods() []method {
	if t.xcount == 0 {
		return nil
	}
	return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.xcount > 0"))[:t.xcount:t.xcount]
}

// resolveNameOff解析与基指针的名称偏移。
// The（*rtype）。nameOff方法是该函数的方便包装器。
// 在运行时包中实现。
func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer

// resolveTypeOff解析基类型的*rtype偏移量。
// The（*rtype）。typeOff方法是该函数的方便包装器。
// 在运行时包中实现。
func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer

// resolveTextOff解析基类型的函数指针偏移量。
// The（*rtype）。textOff方法是这个函数的一个方便的包装器。
// 在运行时包中实现。
func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer

// addReflectOff在运行时添加指向反射查找映射的指针。
// 它返回一个新的ID，可以用作typeOff或textOff，并且将正确解析
// 。在运行时包中实现。
func addReflectOff(ptr unsafe.Pointer) int32

// resolveReflectName在运行时向反射查找映射添加一个名称。
// 它返回一个新名称，可用于引用指针。
func resolveReflectName(n name) nameOff {
	return nameOff(addReflectOff(unsafe.Pointer(n.bytes)))
}

// resolveReflectType在运行时向反射查找映射添加*rtype。
// 它返回一个新的typeOff，可以用来引用指针。
func resolveReflectType(t *rtype) typeOff {
	return typeOff(addReflectOff(unsafe.Pointer(t)))
}

// resolveReflectText在运行时中添加指向反射查找映射的函数指针。它返回一个新的textOff，可用于引用
// 指针。
func resolveReflectText(ptr unsafe.Pointer) textOff {
	return textOff(addReflectOff(ptr))
}

type nameOff int32 // 偏移到名称
type typeOff int32 // 偏移到*rtype 
type textOff int32 // 偏移到文本段顶部

func (t *rtype) nameOff(off nameOff) name {
	return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))}
}

func (t *rtype) typeOff(off typeOff) *rtype {
	return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off)))
}

func (t *rtype) textOff(off textOff) unsafe.Pointer {
	return resolveTextOff(unsafe.Pointer(t), int32(off))
}

func (t *rtype) uncommon() *uncommonType {
	if t.tflag&tflagUncommon == 0 {
		return nil
	}
	switch t.Kind() {
	case Struct:
		return &(*structTypeUncommon)(unsafe.Pointer(t)).u
	case Pointer:
		type u struct {
			ptrType
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	case Func:
		type u struct {
			funcType
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	case Slice:
		type u struct {
			sliceType
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	case Array:
		type u struct {
			arrayType
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	case Chan:
		type u struct {
			chanType
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	case Map:
		type u struct {
			mapType
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	case Interface:
		type u struct {
			interfaceType
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	default:
		type u struct {
			rtype
			u uncommonType
		}
		return &(*u)(unsafe.Pointer(t)).u
	}
}

func (t *rtype) String() string {
	s := t.nameOff(t.str).name()
	if t.tflag&tflagExtraStar != 0 {
		return s[1:]
	}
	return s
}

func (t *rtype) Size() uintptr { return t.size }

func (t *rtype) Bits() int {
	if t == nil {
		panic("reflect: Bits of nil Type")
	}
	k := t.Kind()
	if k < Int || k > Complex128 {
		panic("reflect: Bits of non-arithmetic Type " + t.String())
	}
	return int(t.size) * 8
}

func (t *rtype) Align() int { return int(t.align) }

func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }

func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }

func (t *rtype) pointers() bool { return t.ptrdata != 0 }

func (t *rtype) common() *rtype { return t }

func (t *rtype) exportedMethods() []method {
	ut := t.uncommon()
	if ut == nil {
		return nil
	}
	return ut.exportedMethods()
}

func (t *rtype) NumMethod() int {
	if t.Kind() == Interface {
		tt := (*interfaceType)(unsafe.Pointer(t))
		return tt.NumMethod()
	}
	return len(t.exportedMethods())
}

func (t *rtype) Method(i int) (m Method) {
	if t.Kind() == Interface {
		tt := (*interfaceType)(unsafe.Pointer(t))
		return tt.Method(i)
	}
	methods := t.exportedMethods()
	if i < 0 || i >= len(methods) {
		panic("reflect: Method index out of range")
	}
	p := methods[i]
	pname := t.nameOff(p.name)
	m.Name = pname.name()
	fl := flag(Func)
	mtyp := t.typeOff(p.mtyp)
	ft := (*funcType)(unsafe.Pointer(mtyp))
	in := make([]Type, 0, 1+len(ft.in()))
	in = append(in, t)
	for _, arg := range ft.in() {
		in = append(in, arg)
	}
	out := make([]Type, 0, len(ft.out()))
	for _, ret := range ft.out() {
		out = append(out, ret)
	}
	mt := FuncOf(in, out, ft.IsVariadic())
	m.Type = mt
	tfn := t.textOff(p.tfn)
	fn := unsafe.Pointer(&tfn)
	m.Func = Value{mt.(*rtype), fn, fl}

	m.Index = i
	return m
}

func (t *rtype) MethodByName(name string) (m Method, ok bool) {
	if t.Kind() == Interface {
		tt := (*interfaceType)(unsafe.Pointer(t))
		return tt.MethodByName(name)
	}
	ut := t.uncommon()
	if ut == nil {
		return Method{}, false
	}
	// TODO（mdempsky）：二进制搜索。
	for i, p := range ut.exportedMethods() {
		if t.nameOff(p.name).name() == name {
			return t.Method(i), true
		}
	}
	return Method{}, false
}

func (t *rtype) PkgPath() string {
	if t.tflag&tflagNamed == 0 {
		return ""
	}
	ut := t.uncommon()
	if ut == nil {
		return ""
	}
	return t.nameOff(ut.pkgPath).name()
}

func (t *rtype) hasName() bool {
	return t.tflag&tflagNamed != 0
}

func (t *rtype) Name() string {
	if !t.hasName() {
		return ""
	}
	s := t.String()
	i := len(s) - 1
	sqBrackets := 0
	for i >= 0 && (s[i] != '.' || sqBrackets != 0) {
		switch s[i] {
		case ']':
			sqBrackets++
		case '[':
			sqBrackets--
		}
		i--
	}
	return s[i+1:]
}

func (t *rtype) ChanDir() ChanDir {
	if t.Kind() != Chan {
		panic("reflect: ChanDir of non-chan type " + t.String())
	}
	tt := (*chanType)(unsafe.Pointer(t))
	return ChanDir(tt.dir)
}

func (t *rtype) IsVariadic() bool {
	if t.Kind() != Func {
		panic("reflect: IsVariadic of non-func type " + t.String())
	}
	tt := (*funcType)(unsafe.Pointer(t))
	return tt.outCount&(1<<15) != 0
}

func (t *rtype) Elem() Type {
	switch t.Kind() {
	case Array:
		tt := (*arrayType)(unsafe.Pointer(t))
		return toType(tt.elem)
	case Chan:
		tt := (*chanType)(unsafe.Pointer(t))
		return toType(tt.elem)
	case Map:
		tt := (*mapType)(unsafe.Pointer(t))
		return toType(tt.elem)
	case Pointer:
		tt := (*ptrType)(unsafe.Pointer(t))
		return toType(tt.elem)
	case Slice:
		tt := (*sliceType)(unsafe.Pointer(t))
		return toType(tt.elem)
	}
	panic("reflect: Elem of invalid type " + t.String())
}

func (t *rtype) Field(i int) StructField {
	if t.Kind() != Struct {
		panic("reflect: Field of non-struct type " + t.String())
	}
	tt := (*structType)(unsafe.Pointer(t))
	return tt.Field(i)
}

func (t *rtype) FieldByIndex(index []int) StructField {
	if t.Kind() != Struct {
		panic("reflect: FieldByIndex of non-struct type " + t.String())
	}
	tt := (*structType)(unsafe.Pointer(t))
	return tt.FieldByIndex(index)
}

func (t *rtype) FieldByName(name string) (StructField, bool) {
	if t.Kind() != Struct {
		panic("reflect: FieldByName of non-struct type " + t.String())
	}
	tt := (*structType)(unsafe.Pointer(t))
	return tt.FieldByName(name)
}

func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) {
	if t.Kind() != Struct {
		panic("reflect: FieldByNameFunc of non-struct type " + t.String())
	}
	tt := (*structType)(unsafe.Pointer(t))
	return tt.FieldByNameFunc(match)
}

func (t *rtype) In(i int) Type {
	if t.Kind() != Func {
		panic("reflect: In of non-func type " + t.String())
	}
	tt := (*funcType)(unsafe.Pointer(t))
	return toType(tt.in()[i])
}

func (t *rtype) Key() Type {
	if t.Kind() != Map {
		panic("reflect: Key of non-map type " + t.String())
	}
	tt := (*mapType)(unsafe.Pointer(t))
	return toType(tt.key)
}

func (t *rtype) Len() int {
	if t.Kind() != Array {
		panic("reflect: Len of non-array type " + t.String())
	}
	tt := (*arrayType)(unsafe.Pointer(t))
	return int(tt.len)
}

func (t *rtype) NumField() int {
	if t.Kind() != Struct {
		panic("reflect: NumField of non-struct type " + t.String())
	}
	tt := (*structType)(unsafe.Pointer(t))
	return len(tt.fields)
}

func (t *rtype) NumIn() int {
	if t.Kind() != Func {
		panic("reflect: NumIn of non-func type " + t.String())
	}
	tt := (*funcType)(unsafe.Pointer(t))
	return int(tt.inCount)
}

func (t *rtype) NumOut() int {
	if t.Kind() != Func {
		panic("reflect: NumOut of non-func type " + t.String())
	}
	tt := (*funcType)(unsafe.Pointer(t))
	return len(tt.out())
}

func (t *rtype) Out(i int) Type {
	if t.Kind() != Func {
		panic("reflect: Out of non-func type " + t.String())
	}
	tt := (*funcType)(unsafe.Pointer(t))
	return toType(tt.out()[i])
}

func (t *funcType) in() []*rtype {
	uadd := unsafe.Sizeof(*t)
	if t.tflag&tflagUncommon != 0 {
		uadd += unsafe.Sizeof(uncommonType{})
	}
	if t.inCount == 0 {
		return nil
	}
	return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.inCount:t.inCount]
}

func (t *funcType) out() []*rtype {
	uadd := unsafe.Sizeof(*t)
	if t.tflag&tflagUncommon != 0 {
		uadd += unsafe.Sizeof(uncommonType{})
	}
	outCount := t.outCount & (1<<15 - 1)
	if outCount == 0 {
		return nil
	}
	return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "outCount > 0"))[t.inCount : t.inCount+outCount : t.inCount+outCount]
}

// add返回p+x。
// 
// whySafe字符串被忽略，因此函数仍然像p+x一样高效地内联
// 但是所有调用站点都应该使用该字符串来记录为什么添加是安全的，也就是说，为什么加法
// 不会导致x前进到p的分配
// 的最末端，从而错误地指向内存中的下一个块。
func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
	return unsafe.Pointer(uintptr(p) + x)
}

func (d ChanDir) String() string {
	switch d {
	case SendDir:
		return "chan<-"
	case RecvDir:
		return "<-chan"
	case BothDir:
		return "chan"
	}
	return "ChanDir" + strconv.Itoa(int(d))
}

// 方法返回类型的方法集中的第i个方法。
func (t *interfaceType) Method(i int) (m Method) {
	if i < 0 || i >= len(t.methods) {
		return
	}
	p := &t.methods[i]
	pname := t.nameOff(p.name)
	m.Name = pname.name()
	if !pname.isExported() {
		m.PkgPath = pname.pkgPath()
		if m.PkgPath == "" {
			m.PkgPath = t.pkgPath.name()
		}
	}
	m.Type = toType(t.typeOff(p.typ))
	m.Index = i
	return
}

// NumMethod返回类型的方法集中接口方法的数量。
func (t *interfaceType) NumMethod() int { return len(t.methods) }

// MethodByName方法，该方法在类型的方法集中具有给定的名称。
func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
	if t == nil {
		return
	}
	var p *imethod
	for i := range t.methods {
		p = &t.methods[i]
		if t.nameOff(p.name).name() == name {
			return t.Method(i), true
		}
	}
	return
}

// StructField描述结构中的单个字段。
type StructField struct {
	// Name是字段名。
	Name string

	// PkgPath是限定小写（未报告）
	// 字段名的包路径。对于大写（导出）字段名，它为空。
	// 请参见https:
	PkgPath string

	Type      Type      // 字段类型
	Tag       StructTag // 字段标记字符串
	Offset    uintptr   // 结构内的偏移量，以字节为单位
	Index     []int     // 类型的索引序列。FieldByIndex 
	Anonymous bool      // 是一个嵌入式字段
}

// IsExported报告该字段是否已导出。
func (f StructField) IsExported() bool {
	return f.PkgPath == ""
}

// StructTag是结构字段中的标记字符串。
// 
// 按照惯例，标记字符串是
// 可选的空格分隔键：“值”对的串联。
// 每个键都是非空字符串，由非控制
// 除空格（U+0020'）、引号（U+0022'）、
// 和冒号（U+003A'：'）以外的字符组成。每个值都使用U+0022'”
// 字符和Go string文字语法引用。
type StructTag string

// Get返回与标记字符串中的键关联的值。
// 如果标记中没有这样的键，Get将返回空字符串。
// 如果标签没有常规格式，则Get返回的值
// 未指定。要确定标记是否为
// 显式设置为空字符串，请使用Lookup。
func (tag StructTag) Get(key string) string {
	v, _ := tag.Lookup(key)
	return v
}

// Lookup返回与标记字符串中的键关联的值。
// 如果标记中存在密钥，则返回值（可能为空）。否则，返回的值将是空字符串。
// 确定返回值报告该值是否在标记字符串中显式设置。如果标签没有常规格式，则
// 查找返回的值未指定。
func (tag StructTag) Lookup(key string) (value string, ok bool) {
	// 修改此代码时，也要更新cmd/vet/structtag中的validateStructTag代码
	// 。去

	for tag != "" {
		// 跳过前导空格。
		i := 0
		for i < len(tag) && tag[i] == ' ' {
			i++
		}
		tag = tag[i:]
		if tag == "" {
			break
		}

		// 扫描到结肠。空格、引号或控制字符是语法错误。
		// 严格来说，控制字符包括[0x7f，0x9f]范围，不仅仅是
		// /[0x00，0x1f]，实际上，我们忽略了多字节控制字符
		// 因为检查标记的字节比检查标记的符文更简单。
		i = 0
		for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
			i++
		}
		if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
			break
		}
		name := string(tag[:i])
		tag = tag[i+1:]

		// 扫描带引号的字符串以查找值。
		i = 1
		for i < len(tag) && tag[i] != '"' {
			if tag[i] == '\\' {
				i++
			}
			i++
		}
		if i >= len(tag) {
			break
		}
		qvalue := string(tag[:i+1])
		tag = tag[i+1:]

		if key == name {
			value, err := strconv.Unquote(qvalue)
			if err != nil {
				break
			}
			return value, true
		}
	}
	return "", false
}

// 字段返回第i个结构字段。
func (t *structType) Field(i int) (f StructField) {
	if i < 0 || i >= len(t.fields) {
		panic("reflect: Field index out of bounds")
	}
	p := &t.fields[i]
	f.Type = toType(p.typ)
	f.Name = p.name.name()
	f.Anonymous = p.embedded()
	if !p.name.isExported() {
		f.PkgPath = t.pkgPath.name()
	}
	if tag := p.name.tag(); tag != "" {
		f.Tag = StructTag(tag)
	}
	f.Offset = p.offset()

	// 注意（rsc）：这是接口
	// 中唯一由reflect提供的分配。类型至少在常见情况下，避免这样做是很好的，但我们需要确保reflect的行为不端的客户端不会影响其他reflect的使用。一种可能性是CL 5371098，但我们推迟了丑陋的表现，直到表现出对表演的需求。这是第2320期。
	f.Index = []int{i}
	return
}

// TODO（gri）：如果索引
// 对于FieldByIndex是错误的，是否应该有错误/bool指示器？

// FieldByIndex返回索引对应的嵌套字段。
func (t *structType) FieldByIndex(index []int) (f StructField) {
	f.Type = toType(&t.rtype)
	for i, x := range index {
		if i > 0 {
			ft := f.Type
			if ft.Kind() == Pointer && ft.Elem().Kind() == Struct {
				ft = ft.Elem()
			}
			f.Type = ft
		}
		f = f.Type.Field(x)
	}
	return
}

// fieldScan表示fieldByNameFunc扫描工作列表中的一项。
type fieldScan struct {
	typ   *structType
	index []int
}

// FieldByNameFunc返回结构字段，该字段的名称满足
// match函数，并返回一个布尔值，以指示是否找到该字段。
func (t *structType) FieldByNameFunc(match func(string) bool) (result StructField, ok bool) {
	// 这与Go语言使用的条件相同：在给定的深度级别上，必须有匹配的唯一实例
	// 。如果在
	// 相同深度有多个匹配实例，它们会相互抵消，并在较低级别禁止任何可能的匹配。
	// 该算法是广度优先搜索，每次搜索一个深度级别。

	// 当前和下一个切片是工作队列：
	// 当前列出此深度级别上要访问的字段，
	// 下一个列出下一个较低级别上的字段。
	current := []fieldScan{}
	next := []fieldScan{{typ: t}}

	// nextCount记录嵌入类型已被
	// 遇到并考虑在“下一个”切片中排队的次数。
	// 我们只对第一个队列进行排队，但我们会增加每个队列的计数。
	// 如果一个结构类型T在一个给定的深度级别上可以被多次访问，
	// 那么当我们处理下一个深度级别时，它会自动消失，根本不需要考虑它。
	var nextCount map[*structType]int

	// 已访问的记录已被考虑的结构。
	// 嵌入式指针字段可以在
	// 可访问嵌入式类型的图形中创建循环；我们避免遵循这些循环。
	// 它还避免了重复的工作：如果我们在2级的
	// 嵌入类型t中找不到该字段，那么在4级的嵌入类型t中也找不到该字段。
	visited := map[*structType]bool{}

	for len(next) > 0 {
		current, next = next, current[:0]
		count := nextCount
		nextCount = nil

		// 处理此深度的所有字段，现在列在“当前”中。
		// 循环将在“next”中找到的嵌入字段排队，以便在下一次
		// 迭代期间进行处理。“当前”字段计数的多重性记录在
		// 的“计数”中；“next”字段计数的多重性记录在“nextCount”中。
		for _, scan := range current {
			t := scan.typ
			if visited[t] {
				// 我们以前在更高的层次上研究过这种类型。
				// 更高的级别会掩盖我们现在处于的较低级别，所以这个级别对我们没有用处。别理它。
				continue
			}
			visited[t] = true
			for i := range t.fields {
				f := &t.fields[i]
				// 查找字段f的名称和（对于嵌入字段）类型。
				fname := f.name.name()
				var ntyp *rtype
				if f.embedded() {
					// 类型为T或*T的嵌入字段。
					ntyp = f.typ
					if ntyp.Kind() == Pointer {
						ntyp = ntyp.Elem().common()
					}
				}

				// 是否匹配？
				if match(fname) {
					// 潜在匹配
					if count[t] > 1 || ok {
						// 名称在此级别多次出现：歼灭。
						return StructField{}, false
					}
					result = t.Field(i)
					result.Index = nil
					result.Index = append(result.Index, scan.index...)
					result.Index = append(result.Index, i)
					ok = true
					continue
				}

				// 将嵌入式结构字段排队，以便与下一级进行处理，
				// 但前提是我们尚未在该级别看到匹配，并且只有
				// 如果嵌入式类型尚未排队。
				if ok || ntyp == nil || ntyp.Kind() != Struct {
					continue
				}
				styp := (*structType)(unsafe.Pointer(ntyp))
				if nextCount[styp] > 0 {
					nextCount[styp] = 2 // 精确倍数无关紧要
					continue
				}
				if nextCount == nil {
					nextCount = map[*structType]int{}
				}
				nextCount[styp] = 1
				if count[t] > 1 {
					nextCount[styp] = 2 // 精确倍数无关紧要
				}
				var index []int
				index = append(index, scan.index...)
				index = append(index, i)
				next = append(next, fieldScan{styp, index})
			}
		}
		if ok {
			break
		}
	}
	return
}

// FieldByName返回名为
// 的结构字段，并返回一个布尔值以指示是否找到该字段。
func (t *structType) FieldByName(name string) (f StructField, present bool) {
	// 快速检查顶级名称或不带嵌入字段的结构。
	hasEmbeds := false
	if name != "" {
		for i := range t.fields {
			tf := &t.fields[i]
			if tf.name.name() == name {
				return t.Field(i), true
			}
			if tf.embedded() {
				hasEmbeds = true
			}
		}
	}
	if !hasEmbeds {
		return
	}
	return t.FieldByNameFunc(func(s string) bool { return s == name })
}

// TypeOf返回表示i的动态类型的反射类型。
// 如果i是nil接口值，则TypeOf返回nil。
func TypeOf(i any) Type {
	eface := *(*emptyInterface)(unsafe.Pointer(&i))
	return toType(eface.typ)
}

// ptrMap是指针到的缓存。
var ptrMap sync.Map // map[*rtype]*ptrType 

// PtrTo返回带有元素t的指针类型。例如，如果t表示类型Foo，PtrTo（t）表示*Foo。
// 
// PtrTo是PointerTo的旧拼写。
// 这两个函数的行为相同。
func PtrTo(t Type) Type { return PointerTo(t) }

// PointerTo返回带有元素t的指针类型。例如，如果t表示类型Foo，则PointerTo（t）表示*Foo。
func PointerTo(t Type) Type {
	return t.(*rtype).ptrTo()
}

func (t *rtype) ptrTo() *rtype {
	if t.ptrToThis != 0 {
		return t.typeOff(t.ptrToThis)
	}

	// 检查缓存。
	if pi, ok := ptrMap.Load(t); ok {
		return &pi.(*ptrType).rtype
	}

	// 查看已知类型。
	s := "*" + t.String()
	for _, tt := range typesByString(s) {
		p := (*ptrType)(unsafe.Pointer(tt))
		if p.elem != t {
			continue
		}
		pi, _ := ptrMap.LoadOrStore(t, p)
		return &pi.(*ptrType).rtype
	}

	// 创建一个新的ptrType，以*不安全的描述
	// 开头。指针。
	var iptr any = (*unsafe.Pointer)(nil)
	prototype := *(**ptrType)(unsafe.Pointer(&iptr))
	pp := *prototype

	pp.str = resolveReflectName(newName(s, "", false))
	pp.ptrToThis = 0

	// 对于链接到二进制文件中的类型结构，
	// 编译器提供了一个很好的字符串哈希。
	// 使用
	// FNV-1散列的混合函数来组合
	// 旧散列和新“*”，为新字符串创建一个好的散列。
	pp.hash = fnv1(t.hash, '*')

	pp.elem = t

	pi, _ := ptrMap.LoadOrStore(t, &pp)
	return &pi.(*ptrType).rtype
}

// fnv1使用FNV-1散列函数将字节列表合并到散列x中。
func fnv1(x uint32, list ...byte) uint32 {
	for _, b := range list {
		x = x*16777619 ^ uint32(b)
	}
	return x
}

func (t *rtype) Implements(u Type) bool {
	if u == nil {
		panic("reflect: nil type passed to Type.Implements")
	}
	if u.Kind() != Interface {
		panic("reflect: non-interface type passed to Type.Implements")
	}
	return implements(u.(*rtype), t)
}

func (t *rtype) AssignableTo(u Type) bool {
	if u == nil {
		panic("reflect: nil type passed to Type.AssignableTo")
	}
	uu := u.(*rtype)
	return directlyAssignable(uu, t) || implements(uu, t)
}

func (t *rtype) ConvertibleTo(u Type) bool {
	if u == nil {
		panic("reflect: nil type passed to Type.ConvertibleTo")
	}
	uu := u.(*rtype)
	return convertOp(uu, t) != nil
}

func (t *rtype) Comparable() bool {
	return t.equal != nil
}

// implements报告类型V是否实现了接口类型T。
func implements(T, V *rtype) bool {
	if T.Kind() != Interface {
		return false
	}
	t := (*interfaceType)(unsafe.Pointer(T))
	if len(t.methods) == 0 {
		return true
	}

	// 相同的算法适用于这两种情况，但接口类型和具体类型的
	// 方法表不同，因此代码重复。
	// 在这两种情况下，算法都是同时对两个
	// 列表（T的方法和V的方法）进行线性扫描。
	// 由于方法表以唯一的排序顺序存储
	// （按字母顺序，没有重复的方法名称），因此通过V的方法扫描
	// 必须与T的每个
	// 方法匹配，否则V不实现T.
	// 这让我们在整体线性时间内运行扫描，而不是
	// 简单搜索所需的二次时间。
	// 另见/运行时/iface。去
	if V.Kind() == Interface {
		v := (*interfaceType)(unsafe.Pointer(V))
		i := 0
		for j := 0; j < len(v.methods); j++ {
			tm := &t.methods[i]
			tmName := t.nameOff(tm.name)
			vm := &v.methods[j]
			vmName := V.nameOff(vm.name)
			if vmName.name() == tmName.name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
				if !tmName.isExported() {
					tmPkgPath := tmName.pkgPath()
					if tmPkgPath == "" {
						tmPkgPath = t.pkgPath.name()
					}
					vmPkgPath := vmName.pkgPath()
					if vmPkgPath == "" {
						vmPkgPath = v.pkgPath.name()
					}
					if tmPkgPath != vmPkgPath {
						continue
					}
				}
				if i++; i >= len(t.methods) {
					return true
				}
			}
		}
		return false
	}

	v := V.uncommon()
	if v == nil {
		return false
	}
	i := 0
	vmethods := v.methods()
	for j := 0; j < int(v.mcount); j++ {
		tm := &t.methods[i]
		tmName := t.nameOff(tm.name)
		vm := vmethods[j]
		vmName := V.nameOff(vm.name)
		if vmName.name() == tmName.name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) {
			if !tmName.isExported() {
				tmPkgPath := tmName.pkgPath()
				if tmPkgPath == "" {
					tmPkgPath = t.pkgPath.name()
				}
				vmPkgPath := vmName.pkgPath()
				if vmPkgPath == "" {
					vmPkgPath = V.nameOff(v.pkgPath).name()
				}
				if tmPkgPath != vmPkgPath {
					continue
				}
			}
			if i++; i >= len(t.methods) {
				return true
			}
		}
	}
	return false
}

// SpecialChannel Assignability报告通道类型V的值x是否可以直接分配（使用memmove）到另一个通道类型T。
// https:
// T和V必须是同一类型。
func specialChannelAssignability(T, V *rtype) bool {
	// 特例：
	// x是双向通道值，T是通道类型，
	// x的类型V和T具有相同的元素类型，
	// 并且V或T中至少有一个不是定义的类型。
	return V.ChanDir() == BothDir && (T.Name() == "" || V.Name() == "") && haveIdenticalType(T.Elem(), V.Elem(), true)
}

// directlyAssignable报告是否可以直接将V类型的值x分配给T类型的值。
// https:
// 忽略接口规则（在别处实现）
// 和理想常量规则（运行时没有理想常量）。
func directlyAssignable(T, V *rtype) bool {
	// x的V型与T型相同？
	if T == V {
		return true
	}

	// 否则T和V中至少有一个不能定义
	// 并且它们必须具有相同的类型。
	if T.hasName() && V.hasName() || T.Kind() != V.Kind() {
		return false
	}

	if T.Kind() == Chan && specialChannelAssignability(T, V) {
		return true
	}

	// x的类型T和V必须具有相同的基础类型。
	return haveIdenticalUnderlyingType(T, V, true)
}

func haveIdenticalType(T, V Type, cmpTags bool) bool {
	if cmpTags {
		return T == V
	}

	if T.Name() != V.Name() || T.Kind() != V.Kind() || T.PkgPath() != V.PkgPath() {
		return false
	}

	return haveIdenticalUnderlyingType(T.common(), V.common(), false)
}

func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool {
	if T == V {
		return true
	}

	kind := T.Kind()
	if kind != V.Kind() {
		return false
	}

	// 同类的非复合类型具有相同的基础类型
	// （该类型的预定义实例）。
	if Bool <= kind && kind <= Complex128 || kind == String || kind == UnsafePointer {
		return true
	}

	// 复合类型。
	switch kind {
	case Array:
		return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)

	case Chan:
		return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)

	case Func:
		t := (*funcType)(unsafe.Pointer(T))
		v := (*funcType)(unsafe.Pointer(V))
		if t.outCount != v.outCount || t.inCount != v.inCount {
			return false
		}
		for i := 0; i < t.NumIn(); i++ {
			if !haveIdenticalType(t.In(i), v.In(i), cmpTags) {
				return false
			}
		}
		for i := 0; i < t.NumOut(); i++ {
			if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) {
				return false
			}
		}
		return true

	case Interface:
		t := (*interfaceType)(unsafe.Pointer(T))
		v := (*interfaceType)(unsafe.Pointer(V))
		if len(t.methods) == 0 && len(v.methods) == 0 {
			return true
		}
		// 可能有相同的方法，但仍然需要运行时转换。
		return false

	case Map:
		return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags)

	case Pointer, Slice:
		return haveIdenticalType(T.Elem(), V.Elem(), cmpTags)

	case Struct:
		t := (*structType)(unsafe.Pointer(T))
		v := (*structType)(unsafe.Pointer(V))
		if len(t.fields) != len(v.fields) {
			return false
		}
		if t.pkgPath.name() != v.pkgPath.name() {
			return false
		}
		for i := range t.fields {
			tf := &t.fields[i]
			vf := &v.fields[i]
			if tf.name.name() != vf.name.name() {
				return false
			}
			if !haveIdenticalType(tf.typ, vf.typ, cmpTags) {
				return false
			}
			if cmpTags && tf.name.tag() != vf.name.tag() {
				return false
			}
			if tf.offsetEmbed != vf.offsetEmbed {
				return false
			}
		}
		return true
	}

	return false
}

// typelinks是在包运行时实现的。
// 它返回每个模块中的一个部分，
// 以及每个模块中的一个*rtype偏移量部分。
// 
// 每个模块中的类型按字符串排序。也就是说，第一个
// 第一个模块的两个链接类型是：
// 
// d0:=sections[0]
// t1:=（*rtype）（add（d0，offset[0][0]）
// 
// 请注意，字符串不是类型的唯一标识符：
// 一个给定字符串可以有多个。
// 只包括我们可能想要查找的类型：
// 指针、通道、贴图、切片和数组。
func typelinks() (sections []unsafe.Pointer, offset [][]int32)

func rtypeOff(section unsafe.Pointer, off int32) *rtype {
	return (*rtype)(add(section, uintptr(off), "sizeof(rtype) > 0"))
}

// typesByString返回typelinks（）的子片，其元素具有给定的字符串表示形式。
// 它可能是空的（没有使用该字符串的已知类型），或者可能有多个元素（使用该字符串的多个类型）。
func typesByString(s string) []*rtype {
	sections, offset := typelinks()
	var ret []*rtype

	for offsI, offs := range offset {
		section := sections[offsI]

		// 我们正在寻找字符串变成>=s的第一个索引i。
		// 这是sort的一个副本。搜索，用（*typ[h].String（）>=s）替换f（h）。
		i, j := 0, len(offs)
		for i < j {
			h := i + (j-i)>>1 // 计算h时避免溢出
			// i≤ h<j 
			if !(rtypeOff(section, offs[h]).String() >= s) {
				i = h + 1 // 保留f（i-1）=假
			} else {
				j = h // 保留f（j）=真
			}
		}
		// i==j，f（i-1）=假，f（j）（=f（i））==真=>答案是i。

		// 找到第一个线性向前扫描以查找最后一个。
		// 我们可以进行第二次二进制搜索，但调用者还是要进行线性扫描。
		for j := i; j < len(offs); j++ {
			typ := rtypeOff(section, offs[j])
			if typ.String() != s {
				break
			}
			ret = append(ret, typ)
		}
	}
	return ret
}

// lookupCache缓存查找的数组、ChanOf、MapOf和SliceOf。
var lookupCache sync.Map // map[cacheKey]*rtype 

// cacheKey是在lookupCache中使用的密钥。
// 四个值描述了我们正在寻找的任何类型：
// 类型种类、一个或两个子类型和一个额外的整数。
type cacheKey struct {
	kind  Kind
	t1    *rtype
	t2    *rtype
	extra uintptr
}

// 函数lookupcache缓存函数查找。
// FuncOf不共享公共lookupCache，因为cacheKey不足以明确表示函数。
var funcLookupCache struct {
	sync.Mutex // Guards在m上存储（但不加载）。

	// m是一个映射[uint32][]*r类型，由FuncOf中计算的哈希键控。
	// m的元素是仅附加的，因此可以安全地进行并发读取。
	m sync.Map
}

// ChanOf返回具有给定方向和元素类型的通道类型。例如，如果t代表int，ChanOf（RecvDir，t）代表<-chan int。
// 
// gc运行时对通道元素类型施加了64 kB的限制。
// 如果t的大小等于或超过这个限制，就会出现恐慌。
func ChanOf(dir ChanDir, t Type) Type {
	typ := t.(*rtype)

	// 在缓存中查找。
	ckey := cacheKey{Chan, typ, nil, uintptr(dir)}
	if ch, ok := lookupCache.Load(ckey); ok {
		return ch.(*rtype)
	}

	// 此限制由gc编译器和运行时施加。
	if typ.size >= 1<<16 {
		panic("reflect.ChanOf: element size too large")
	}

	// 查看已知类型。
	var s string
	switch dir {
	default:
		panic("reflect.ChanOf: invalid dir")
	case SendDir:
		s = "chan<- " + typ.String()
	case RecvDir:
		s = "<-chan " + typ.String()
	case BothDir:
		typeStr := typ.String()
		if typeStr[0] == '<' {
			// 类型为recv chan，需要括号“<-”与最左边的
			// chan可能，请参阅：
			// /*https:
			// /*https:
			s = "chan (" + typeStr + ")"
		} else {
			s = "chan " + typeStr
		}
	}
	for _, tt := range typesByString(s) {
		ch := (*chanType)(unsafe.Pointer(tt))
		if ch.elem == typ && ch.dir == uintptr(dir) {
			ti, _ := lookupCache.LoadOrStore(ckey, tt)
			return ti.(Type)
		}
	}

	// 创建频道类型。
	var ichan any = (chan unsafe.Pointer)(nil)
	prototype := *(**chanType)(unsafe.Pointer(&ichan))
	ch := *prototype
	ch.tflag = tflagRegularMemory
	ch.dir = uintptr(dir)
	ch.str = resolveReflectName(newName(s, "", false))
	ch.hash = fnv1(typ.hash, 'c', byte(dir))
	ch.elem = typ

	ti, _ := lookupCache.LoadOrStore(ckey, &ch.rtype)
	return ti.(Type)
}

// MapOf返回具有给定键和元素类型的映射类型。
// 例如，如果k代表int，e代表string，则
// MapOf（k，e）代表map[int]string。
// 
// 如果密钥类型不是有效的映射密钥类型（即，如果它确实是
// 未实现Go的==运算符），则映射恐慌。
func MapOf(key, elem Type) Type {
	ktyp := key.(*rtype)
	etyp := elem.(*rtype)

	if ktyp.equal == nil {
		panic("reflect.MapOf: invalid key type " + ktyp.String())
	}

	// 在缓存中查找。
	ckey := cacheKey{Map, ktyp, etyp, 0}
	if mt, ok := lookupCache.Load(ckey); ok {
		return mt.(Type)
	}

	// 查看已知类型。
	s := "map[" + ktyp.String() + "]" + etyp.String()
	for _, tt := range typesByString(s) {
		mt := (*mapType)(unsafe.Pointer(tt))
		if mt.key == ktyp && mt.elem == etyp {
			ti, _ := lookupCache.LoadOrStore(ckey, tt)
			return ti.(Type)
		}
	}

	// 创建一个映射类型。
	// 注意：标记值必须与TMAP案例中使用的值匹配
	// in/cmd/compile/internal/reflectdata/reflect。go:writeType。
	var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
	mt := **(**mapType)(unsafe.Pointer(&imap))
	mt.str = resolveReflectName(newName(s, "", false))
	mt.tflag = 0
	mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
	mt.key = ktyp
	mt.elem = etyp
	mt.bucket = bucketOf(ktyp, etyp)
	mt.hasher = func(p unsafe.Pointer, seed uintptr) uintptr {
		return typehash(ktyp, p, seed)
	}
	mt.flags = 0
	if ktyp.size > maxKeySize {
		mt.keysize = uint8(goarch.PtrSize)
		mt.flags |= 1 // 间接键
	} else {
		mt.keysize = uint8(ktyp.size)
	}
	if etyp.size > maxValSize {
		mt.valuesize = uint8(goarch.PtrSize)
		mt.flags |= 2 // 间接值
	} else {
		mt.valuesize = uint8(etyp.size)
	}
	mt.bucketsize = uint16(mt.bucket.size)
	if isReflexive(ktyp) {
		mt.flags |= 4
	}
	if needKeyUpdate(ktyp) {
		mt.flags |= 8
	}
	if hashMightPanic(ktyp) {
		mt.flags |= 16
	}
	mt.ptrToThis = 0

	ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)
	return ti.(Type)
}

// TODO（crawshaw）：由于这些funcTypeFixedN结构没有方法，
// 可以在运行时使用StructOf函数定义它们。
type funcTypeFixed4 struct {
	funcType
	args [4]*rtype
}
type funcTypeFixed8 struct {
	funcType
	args [8]*rtype
}
type funcTypeFixed16 struct {
	funcType
	args [16]*rtype
}
type funcTypeFixed32 struct {
	funcType
	args [32]*rtype
}
type funcTypeFixed64 struct {
	funcType
	args [64]*rtype
}
type funcTypeFixed128 struct {
	funcType
	args [128]*rtype
}

// FuncOf返回具有给定参数和结果类型的函数类型。
// 例如，如果k代表int，e代表string，
// FuncOf（[]Type{k}，[]Type{e}，false）代表func（int）string。
// 
// 变量参数控制函数是否为变量。如果in[len（in）-1]不代表一个切片，且变量为
// 则会恐慌。
func FuncOf(in, out []Type, variadic bool) Type {
	if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) {
		panic("reflect.FuncOf: last arg of variadic func must be slice")
	}

	// 创建一个函数类型。
	var ifunc any = (func())(nil)
	prototype := *(**funcType)(unsafe.Pointer(&ifunc))
	n := len(in) + len(out)

	var ft *funcType
	var args []*rtype
	switch {
	case n <= 4:
		fixed := new(funcTypeFixed4)
		args = fixed.args[:0:len(fixed.args)]
		ft = &fixed.funcType
	case n <= 8:
		fixed := new(funcTypeFixed8)
		args = fixed.args[:0:len(fixed.args)]
		ft = &fixed.funcType
	case n <= 16:
		fixed := new(funcTypeFixed16)
		args = fixed.args[:0:len(fixed.args)]
		ft = &fixed.funcType
	case n <= 32:
		fixed := new(funcTypeFixed32)
		args = fixed.args[:0:len(fixed.args)]
		ft = &fixed.funcType
	case n <= 64:
		fixed := new(funcTypeFixed64)
		args = fixed.args[:0:len(fixed.args)]
		ft = &fixed.funcType
	case n <= 128:
		fixed := new(funcTypeFixed128)
		args = fixed.args[:0:len(fixed.args)]
		ft = &fixed.funcType
	default:
		panic("reflect.FuncOf: too many arguments")
	}
	*ft = *prototype

	// 构建一个散列并以最少的方式填充ft.
	var hash uint32
	for _, in := range in {
		t := in.(*rtype)
		args = append(args, t)
		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
	}
	if variadic {
		hash = fnv1(hash, 'v')
	}
	hash = fnv1(hash, '.')
	for _, out := range out {
		t := out.(*rtype)
		args = append(args, t)
		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
	}
	if len(args) > 50 {
		panic("reflect.FuncOf does not support more than 50 arguments")
	}
	ft.tflag = 0
	ft.hash = hash
	ft.inCount = uint16(len(in))
	ft.outCount = uint16(len(out))
	if variadic {
		ft.outCount |= 1 << 15
	}

	// 在缓存中查找。
	if ts, ok := funcLookupCache.m.Load(hash); ok {
		for _, t := range ts.([]*rtype) {
			if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
				return t
			}
		}
	}

	// 不在缓存中，请锁定并重试。
	funcLookupCache.Lock()
	defer funcLookupCache.Unlock()
	if ts, ok := funcLookupCache.m.Load(hash); ok {
		for _, t := range ts.([]*rtype) {
			if haveIdenticalUnderlyingType(&ft.rtype, t, true) {
				return t
			}
		}
	}

	addToCache := func(tt *rtype) Type {
		var rts []*rtype
		if rti, ok := funcLookupCache.m.Load(hash); ok {
			rts = rti.([]*rtype)
		}
		funcLookupCache.m.Store(hash, append(rts, tt))
		return tt
	}

	// 在已知类型中查找相同的字符串表示形式。
	str := funcStr(ft)
	for _, tt := range typesByString(str) {
		if haveIdenticalUnderlyingType(&ft.rtype, tt, true) {
			return addToCache(tt)
		}
	}

	// 填充ft的剩余字段并存储在缓存中。
	ft.str = resolveReflectName(newName(str, "", false))
	ft.ptrToThis = 0
	return addToCache(&ft.rtype)
}

// funcStr构建funcType的字符串表示形式。
func funcStr(ft *funcType) string {
	repr := make([]byte, 0, 64)
	repr = append(repr, "func("...)
	for i, t := range ft.in() {
		if i > 0 {
			repr = append(repr, ", "...)
		}
		if ft.IsVariadic() && i == int(ft.inCount)-1 {
			repr = append(repr, "..."...)
			repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.String()...)
		} else {
			repr = append(repr, t.String()...)
		}
	}
	repr = append(repr, ')')
	out := ft.out()
	if len(out) == 1 {
		repr = append(repr, ' ')
	} else if len(out) > 1 {
		repr = append(repr, " ("...)
	}
	for i, t := range out {
		if i > 0 {
			repr = append(repr, ", "...)
		}
		repr = append(repr, t.String()...)
	}
	if len(out) > 1 {
		repr = append(repr, ')')
	}
	return string(repr)
}

// isReflexive报告类型上的==操作是否为自反操作。
// 也就是说，对于类型为t的所有值x，x==x。
func isReflexive(t *rtype) bool {
	switch t.Kind() {
	case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, String, UnsafePointer:
		return true
	case Float32, Float64, Complex64, Complex128, Interface:
		return false
	case Array:
		tt := (*arrayType)(unsafe.Pointer(t))
		return isReflexive(tt.elem)
	case Struct:
		tt := (*structType)(unsafe.Pointer(t))
		for _, f := range tt.fields {
			if !isReflexive(f.typ) {
				return false
			}
		}
		return true
	default:
		// Func、Map、Slice、无效
		panic("isReflexive called on non-key type " + t.String())
	}
}

// needKeyUpdate报告Map覆盖是否需要复制密钥。
func needKeyUpdate(t *rtype) bool {
	switch t.Kind() {
	case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, UnsafePointer:
		return false
	case Float32, Float64, Complex64, Complex128, Interface, String:
		// 浮动键可以从+0更新到-0。
		// 可以更新字符串键以使用较小的备份存储。
		// 接口中可能有字符串浮动。
		return true
	case Array:
		tt := (*arrayType)(unsafe.Pointer(t))
		return needKeyUpdate(tt.elem)
	case Struct:
		tt := (*structType)(unsafe.Pointer(t))
		for _, f := range tt.fields {
			if needKeyUpdate(f.typ) {
				return true
			}
		}
		return false
	default:
		// Func，Map，Slice，Invalid 
		panic("needKeyUpdate called on non-key type " + t.String())
	}
}

// hashMightPanic报告类型为t的映射键的散列是否会死机。
func hashMightPanic(t *rtype) bool {
	switch t.Kind() {
	case Interface:
		return true
	case Array:
		tt := (*arrayType)(unsafe.Pointer(t))
		return hashMightPanic(tt.elem)
	case Struct:
		tt := (*structType)(unsafe.Pointer(t))
		for _, f := range tt.fields {
			if hashMightPanic(f.typ) {
				return true
			}
		}
		return false
	default:
		return false
	}
}

// 确保这些例程与../保持同步/运行时/映射。去
// 这些类型只存在于GC中，所以我们只填写GC相关信息。
// 目前，这只是大小和GC程序。我们还填写字符串
// 以供可能的调试使用。
const (
	bucketSize uintptr = 8
	maxKeySize uintptr = 128
	maxValSize uintptr = 128
)

func bucketOf(ktyp, etyp *rtype) *rtype {
	if ktyp.size > maxKeySize {
		ktyp = PointerTo(ktyp).(*rtype)
	}
	if etyp.size > maxValSize {
		etyp = PointerTo(etyp).(*rtype)
	}

	// 准备GC数据（如有）。
	// 一个bucket最多是bucketSize*（1+maxKeySize+maxValSize）+2*ptrSize字节，
	// 或2072字节，或259个指针大小的字，或33字节的指针位图。
	// 请注意，由于已知密钥和值<=128字节，
	// 它们保证有位图，而不是GC程序。
	var gcdata *byte
	var ptrdata uintptr
	var overflowPad uintptr

	size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + goarch.PtrSize
	if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 {
		panic("reflect: bad size computation in MapOf")
	}

	if ktyp.ptrdata != 0 || etyp.ptrdata != 0 {
		nptr := (bucketSize*(1+ktyp.size+etyp.size) + goarch.PtrSize) / goarch.PtrSize
		mask := make([]byte, (nptr+7)/8)
		base := bucketSize / goarch.PtrSize

		if ktyp.ptrdata != 0 {
			emitGCMask(mask, base, ktyp, bucketSize)
		}
		base += bucketSize * ktyp.size / goarch.PtrSize

		if etyp.ptrdata != 0 {
			emitGCMask(mask, base, etyp, bucketSize)
		}
		base += bucketSize * etyp.size / goarch.PtrSize
		base += overflowPad / goarch.PtrSize

		word := base
		mask[word/8] |= 1 << (word % 8)
		gcdata = &mask[0]
		ptrdata = (word + 1) * goarch.PtrSize

		// 溢出字必须是最后一个
		if ptrdata != size {
			panic("reflect: bad layout computation in MapOf")
		}
	}

	b := &rtype{
		align:   goarch.PtrSize,
		size:    size,
		kind:    uint8(Struct),
		ptrdata: ptrdata,
		gcdata:  gcdata,
	}
	if overflowPad > 0 {
		b.align = 8
	}
	s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"
	b.str = resolveReflectName(newName(s, "", false))
	return b
}

func (t *rtype) gcSlice(begin, end uintptr) []byte {
	return (*[1 << 30]byte)(unsafe.Pointer(t.gcdata))[begin:end:end]
}

// emitGCMask将[n]类型的GC掩码写入out，从位
// 偏移基开始。
func emitGCMask(out []byte, base uintptr, typ *rtype, n uintptr) {
	if typ.kind&kindGCProg != 0 {
		panic("reflect: unexpected GC program")
	}
	ptrs := typ.ptrdata / goarch.PtrSize
	words := typ.size / goarch.PtrSize
	mask := typ.gcSlice(0, (ptrs+7)/8)
	for j := uintptr(0); j < ptrs; j++ {
		if (mask[j/8]>>(j%8))&1 != 0 {
			for i := uintptr(0); i < n; i++ {
				k := base + i*words + j
				out[k/8] |= 1 << (k % 8)
			}
		}
	}
}

// appendGCProg将用于
// typ的第一个ptrdata字节的GC程序追加到dst，并返回扩展片。
func appendGCProg(dst []byte, typ *rtype) []byte {
	if typ.kind&kindGCProg != 0 {
		// 元素有GC程序；发射一个元素。
		n := uintptr(*(*uint32)(unsafe.Pointer(typ.gcdata)))
		prog := typ.gcSlice(4, 4+n-1)
		return append(dst, prog...)
	}

	// 元素很小，带有指针掩码；用作文字位。
	ptrs := typ.ptrdata / goarch.PtrSize
	mask := typ.gcSlice(0, (ptrs+7)/8)

	// 发出120位的完整字节块（最大值为127，但我们避免使用部分字节）。
	for ; ptrs > 120; ptrs -= 120 {
		dst = append(dst, 120)
		dst = append(dst, mask[:15]...)
		mask = mask[15:]
	}

	dst = append(dst, byte(ptrs))
	dst = append(dst, mask...)
	return dst
}

// SliceOf返回元素类型为t的切片类型。例如，如果t表示int，SliceOf（t）表示[]int。
func SliceOf(t Type) Type {
	typ := t.(*rtype)

	// 在缓存中查找。
	ckey := cacheKey{Slice, typ, nil, 0}
	if slice, ok := lookupCache.Load(ckey); ok {
		return slice.(Type)
	}

	// 查看已知类型。
	s := "[]" + typ.String()
	for _, tt := range typesByString(s) {
		slice := (*sliceType)(unsafe.Pointer(tt))
		if slice.elem == typ {
			ti, _ := lookupCache.LoadOrStore(ckey, tt)
			return ti.(Type)
		}
	}

	// 制作一个切片类型。
	var islice any = ([]unsafe.Pointer)(nil)
	prototype := *(**sliceType)(unsafe.Pointer(&islice))
	slice := *prototype
	slice.tflag = 0
	slice.str = resolveReflectName(newName(s, "", false))
	slice.hash = fnv1(typ.hash, '[')
	slice.elem = typ
	slice.ptrToThis = 0

	ti, _ := lookupCache.LoadOrStore(ckey, &slice.rtype)
	return ti.(Type)
}

// structLookupCache缓存查找的结构。
// StructOf不共享公共查找缓存，因为我们需要锁定与*structTypeFixedN关联的内存。
var structLookupCache struct {
	sync.Mutex // Guards在m上存储（但不加载）。

	// m是一个map[uint32][]类型，由StructOf中计算的哈希键控。
	// m中的元素是仅附加的，因此可以安全地进行并发读取。
	m sync.Map
}

type structTypeUncommon struct {
	structType
	u uncommonType
}

// isLetter报告给定的“符文”是否被归类为字母。
func isLetter(ch rune) bool {
	return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch)
}

// isValidFieldName检查字符串是否为有效（结构）字段名。
// 
// 根据语言规范，字段名应该是标识符。
// 
// 标识符=字母{letter | unicode_digit}。
// letter=unicode|字母|“|”。
func isValidFieldName(fieldName string) bool {
	for i, c := range fieldName {
		if i == 0 && !isLetter(c) {
			return false
		}

		if !(isLetter(c) || unicode.IsDigit(c)) {
			return false
		}
	}

	return len(fieldName) > 0
}

// StructOf返回包含字段的结构类型。
// 编译器会忽略并计算偏移量和索引字段，就像它们是
// 一样。
// 
// StructOf当前不会为嵌入的
// 字段生成包装方法，如果传递的是未报告的StructFields，则会生成垃圾邮件。
// 这些限制可能会在未来的版本中取消。
func StructOf(fields []StructField) Type {
	var (
		hash       = fnv1(0, []byte("struct {")...)
		size       uintptr
		typalign   uint8
		comparable = true
		methods    []method

		fs   = make([]structField, len(fields))
		repr = make([]byte, 0, 64)
		fset = map[string]struct{}{} // 字段名称

		hasGCProg = false // 记录结构字段类型是否具有GCProg 
	)

	lastzero := uintptr(0)
	repr = append(repr, "struct {"...)
	pkgpath := ""
	for i, field := range fields {
		if field.Name == "" {
			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name")
		}
		if !isValidFieldName(field.Name) {
			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has invalid name")
		}
		if field.Type == nil {
			panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
		}
		f, fpkgpath := runtimeStructField(field)
		ft := f.typ
		if ft.kind&kindGCProg != 0 {
			hasGCProg = true
		}
		if fpkgpath != "" {
			if pkgpath == "" {
				pkgpath = fpkgpath
			} else if pkgpath != fpkgpath {
				panic("reflect.Struct: fields with different PkgPath " + pkgpath + " and " + fpkgpath)
			}
		}

		// 更新字符串和哈希
		name := f.name.name()
		hash = fnv1(hash, []byte(name)...)
		repr = append(repr, (" " + name)...)
		if f.embedded() {
			// 嵌入字段
			if f.typ.Kind() == Pointer {
				// 嵌入**和*接口{}是非法的
				elem := ft.Elem()
				if k := elem.Kind(); k == Pointer || k == Interface {
					panic("reflect.StructOf: illegal embedded field type " + ft.String())
				}
			}

			switch f.typ.Kind() {
			case Interface:
				ift := (*interfaceType)(unsafe.Pointer(ft))
				for im, m := range ift.methods {
					if ift.nameOff(m.name).pkgPath() != "" {
						// TODO（sbinet）。第15924期。
						panic("reflect: embedded interface with unexported method(s) not implemented")
					}

					var (
						mtyp    = ift.typeOff(m.typ)
						ifield  = i
						imethod = im
						ifn     Value
						tfn     Value
					)

					if ft.kind&kindDirectIface != 0 {
						tfn = MakeFunc(mtyp, func(in []Value) []Value {
							var args []Value
							var recv = in[0]
							if len(in) > 1 {
								args = in[1:]
							}
							return recv.Field(ifield).Method(imethod).Call(args)
						})
						ifn = MakeFunc(mtyp, func(in []Value) []Value {
							var args []Value
							var recv = in[0]
							if len(in) > 1 {
								args = in[1:]
							}
							return recv.Field(ifield).Method(imethod).Call(args)
						})
					} else {
						tfn = MakeFunc(mtyp, func(in []Value) []Value {
							var args []Value
							var recv = in[0]
							if len(in) > 1 {
								args = in[1:]
							}
							return recv.Field(ifield).Method(imethod).Call(args)
						})
						ifn = MakeFunc(mtyp, func(in []Value) []Value {
							var args []Value
							var recv = Indirect(in[0])
							if len(in) > 1 {
								args = in[1:]
							}
							return recv.Field(ifield).Method(imethod).Call(args)
						})
					}

					methods = append(methods, method{
						name: resolveReflectName(ift.nameOff(m.name)),
						mtyp: resolveReflectType(mtyp),
						ifn:  resolveReflectText(unsafe.Pointer(&ifn)),
						tfn:  resolveReflectText(unsafe.Pointer(&tfn)),
					})
				}
			case Pointer:
				ptr := (*ptrType)(unsafe.Pointer(ft))
				if unt := ptr.uncommon(); unt != nil {
					if i > 0 && unt.mcount > 0 {
						// 第15924期。
						panic("reflect: embedded type with methods not implemented if type is not first field")
					}
					if len(fields) > 1 {
						panic("reflect: embedded type with methods not implemented if there is more than one field")
					}
					for _, m := range unt.methods() {
						mname := ptr.nameOff(m.name)
						if mname.pkgPath() != "" {
							// TODO（sbinet）。
							// 第15924期。
							panic("reflect: embedded interface with unexported method(s) not implemented")
						}
						methods = append(methods, method{
							name: resolveReflectName(mname),
							mtyp: resolveReflectType(ptr.typeOff(m.mtyp)),
							ifn:  resolveReflectText(ptr.textOff(m.ifn)),
							tfn:  resolveReflectText(ptr.textOff(m.tfn)),
						})
					}
				}
				if unt := ptr.elem.uncommon(); unt != nil {
					for _, m := range unt.methods() {
						mname := ptr.nameOff(m.name)
						if mname.pkgPath() != "" {
							// TODO（sbinet）
							// 第15924期。
							panic("reflect: embedded interface with unexported method(s) not implemented")
						}
						methods = append(methods, method{
							name: resolveReflectName(mname),
							mtyp: resolveReflectType(ptr.elem.typeOff(m.mtyp)),
							ifn:  resolveReflectText(ptr.elem.textOff(m.ifn)),
							tfn:  resolveReflectText(ptr.elem.textOff(m.tfn)),
						})
					}
				}
			default:
				if unt := ft.uncommon(); unt != nil {
					if i > 0 && unt.mcount > 0 {
						// 第15924期。
						panic("reflect: embedded type with methods not implemented if type is not first field")
					}
					if len(fields) > 1 && ft.kind&kindDirectIface != 0 {
						panic("reflect: embedded type with methods not implemented for non-pointer type")
					}
					for _, m := range unt.methods() {
						mname := ft.nameOff(m.name)
						if mname.pkgPath() != "" {
							// TODO（sbinet）
							// 第15924期。
							panic("reflect: embedded interface with unexported method(s) not implemented")
						}
						methods = append(methods, method{
							name: resolveReflectName(mname),
							mtyp: resolveReflectType(ft.typeOff(m.mtyp)),
							ifn:  resolveReflectText(ft.textOff(m.ifn)),
							tfn:  resolveReflectText(ft.textOff(m.tfn)),
						})

					}
				}
			}
		}
		if _, dup := fset[name]; dup && name != "_" {
			panic("reflect.StructOf: duplicate field " + name)
		}
		fset[name] = struct{}{}

		hash = fnv1(hash, byte(ft.hash>>24), byte(ft.hash>>16), byte(ft.hash>>8), byte(ft.hash))

		repr = append(repr, (" " + ft.String())...)
		if f.name.hasTag() {
			hash = fnv1(hash, []byte(f.name.tag())...)
			repr = append(repr, (" " + strconv.Quote(f.name.tag()))...)
		}
		if i < len(fields)-1 {
			repr = append(repr, ';')
		}

		comparable = comparable && (ft.equal != nil)

		offset := align(size, uintptr(ft.align))
		if ft.align > typalign {
			typalign = ft.align
		}
		size = offset + ft.size
		f.offsetEmbed |= offset << 1

		if ft.size == 0 {
			lastzero = size
		}

		fs[i] = f
	}

	if size > 0 && lastzero == size {
		// 这是一个非零大小的结构，以
		// 零大小字段结尾。我们添加了一个额外的填充字节，
		// 以确保获取最终的
		// 零大小字段的地址不能生成指向堆中下一个对象的指针。见第9401期。
		size++
	}

	var typ *structType
	var ut *uncommonType

	if len(methods) == 0 {
		t := new(structTypeUncommon)
		typ = &t.structType
		ut = &t.u
	} else {
		// 表示结构的*rtype后面紧跟着一个
		// 表示附加到
		// 结构的方法的方法对象数组。要为运行时生成的类型获得相同的布局，我们需要一个数组直接跟随UncoMonType内存。
		// 类似的策略用于funcTypeFixed4。。。功能类型固定。
		tt := New(StructOf([]StructField{
			{Name: "S", Type: TypeOf(structType{})},
			{Name: "U", Type: TypeOf(uncommonType{})},
			{Name: "M", Type: ArrayOf(len(methods), TypeOf(methods[0]))},
		}))

		typ = (*structType)(tt.Elem().Field(0).Addr().UnsafePointer())
		ut = (*uncommonType)(tt.Elem().Field(1).Addr().UnsafePointer())

		copy(tt.Elem().Field(2).Slice(0, len(methods)).Interface().([]method), methods)
	}
	// TODO（sbinet）：一旦我们允许嵌入多个类型，
	// 方法将需要像编译器那样进行排序。
	// TODO（sbinet）：一旦我们允许非导出方法，我们将
	// 需要计算xcount作为导出方法的数量。
	ut.mcount = uint16(len(methods))
	ut.xcount = ut.mcount
	ut.moff = uint32(unsafe.Sizeof(uncommonType{}))

	if len(fs) > 0 {
		repr = append(repr, ' ')
	}
	repr = append(repr, '}')
	hash = fnv1(hash, '}')
	str := string(repr)

	// 将大小四舍五入为路线的倍数。
	size = align(size, uintptr(typalign))

	// 创建结构类型。
	var istruct any = struct{}{}
	prototype := *(**structType)(unsafe.Pointer(&istruct))
	*typ = *prototype
	typ.fields = fs
	if pkgpath != "" {
		typ.pkgPath = newName(pkgpath, "", false)
	}

	// 在缓存中查找。
	if ts, ok := structLookupCache.m.Load(hash); ok {
		for _, st := range ts.([]Type) {
			t := st.common()
			if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
				return t
			}
		}
	}

	// 不在缓存中，请锁定并重试。
	structLookupCache.Lock()
	defer structLookupCache.Unlock()
	if ts, ok := structLookupCache.m.Load(hash); ok {
		for _, st := range ts.([]Type) {
			t := st.common()
			if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
				return t
			}
		}
	}

	addToCache := func(t Type) Type {
		var ts []Type
		if ti, ok := structLookupCache.m.Load(hash); ok {
			ts = ti.([]Type)
		}
		structLookupCache.m.Store(hash, append(ts, t))
		return t
	}

	// 查看已知类型。
	for _, t := range typesByString(str) {
		if haveIdenticalUnderlyingType(&typ.rtype, t, true) {
			// 即使't'不是带有方法的structType，我们也应该确定
			// 因为除非设置了
			// tflag&tflagUncommonType，否则不会访问'u uncommonType'字段。
			return addToCache(t)
		}
	}

	typ.str = resolveReflectName(newName(str, "", false))
	typ.tflag = 0 // TODO:set-tflagRegularMemory 
	typ.hash = hash
	typ.size = size
	typ.ptrdata = typeptrdata(typ.common())
	typ.align = typalign
	typ.fieldAlign = typalign
	typ.ptrToThis = 0
	if len(methods) > 0 {
		typ.tflag |= tflagUncommon
	}

	if hasGCProg {
		lastPtrField := 0
		for i, ft := range fs {
			if ft.typ.pointers() {
				lastPtrField = i
			}
		}
		prog := []byte{0, 0, 0, 0} // 将是prog的长度
		var off uintptr
		for i, ft := range fs {
			if i > lastPtrField {
				// gcprog不应在
				// 包含指针数据的最后一个字段
				break
			}
			if !ft.typ.pointers() {
				// 忽略无指针字段之后的任何字段。
				continue
			}
			// 用零填充此字段的开头。
			if ft.offset() > off {
				n := (ft.offset() - off) / goarch.PtrSize
				prog = append(prog, 0x01, 0x00) // 发出一个0位
				if n > 1 {
					prog = append(prog, 0x81)      // 重复上一位
					prog = appendVarint(prog, n-1) // n-1次
				}
				off = ft.offset()
			}

			prog = appendGCProg(prog, ft.typ)
			off += ft.typ.ptrdata
		}
		prog = append(prog, 0)
		*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
		typ.kind |= kindGCProg
		typ.gcdata = &prog[0]
	} else {
		typ.kind &^= kindGCProg
		bv := new(bitVector)
		addTypeBits(bv, 0, typ.common())
		if len(bv.data) > 0 {
			typ.gcdata = &bv.data[0]
		}
	}
	typ.equal = nil
	if comparable {
		typ.equal = func(p, q unsafe.Pointer) bool {
			for _, ft := range typ.fields {
				pi := add(p, ft.offset(), "&x.field safe")
				qi := add(q, ft.offset(), "&x.field safe")
				if !ft.typ.equal(pi, qi) {
					return false
				}
			}
			return true
		}
	}

	switch {
	case len(fs) == 1 && !ifaceIndir(fs[0].typ):
		// 1 direct iface类型的结构可以是direct 
		typ.kind |= kindDirectIface
	default:
		typ.kind &^= kindDirectIface
	}

	return addToCache(&typ.rtype)
}

// runtimeStructField接受传递给StructOf的StructField值，
// 返回
// StructField类型的相应内部表示，以及用于此字段的pkgpath值。
func runtimeStructField(field StructField) (structField, string) {
	if field.Anonymous && field.PkgPath != "" {
		panic("reflect.StructOf: field \"" + field.Name + "\" is anonymous but has PkgPath set")
	}

	if field.IsExported() {
		// 尽最大努力检查滥用情况。
		// 由于此字段将被视为导出字段，因此如果Unicode小写字母漏掉，不会造成太大伤害。
		c := field.Name[0]
		if 'a' <= c && c <= 'z' || c == '_' {
			panic("reflect.StructOf: field \"" + field.Name + "\" is unexported but missing PkgPath")
		}
	}

	offsetEmbed := uintptr(0)
	if field.Anonymous {
		offsetEmbed |= 1
	}

	resolveReflectType(field.Type.common()) // 运行时安装
	f := structField{
		name:        newName(field.Name, string(field.Tag), field.IsExported()),
		typ:         field.Type.common(),
		offsetEmbed: offsetEmbed,
	}
	return f, field.PkgPath
}

// typeptrdata返回包含指针数据的t 
// 前缀的字节长度。这个偏移量之后的任何东西都是标量数据。
// 与…保持同步/cmd/compile/internal/reflectdata/reflect。转到
func typeptrdata(t *rtype) uintptr {
	switch t.Kind() {
	case Struct:
		st := (*structType)(unsafe.Pointer(t))
		// 找到最后一个有指针的字段。
		field := -1
		for i := range st.fields {
			ft := st.fields[i].typ
			if ft.pointers() {
				field = i
			}
		}
		if field == -1 {
			return 0
		}
		f := st.fields[field]
		return f.offset() + f.typ.ptrdata

	default:
		panic("reflect.typeptrdata: unexpected type, " + t.String())
	}
}

// 参见cmd/compile/internal/reflectdata/reflect。求常数的导数。
const maxPtrmaskBytes = 2048

// ArrayOf返回给定长度和元素类型的数组类型。
// 例如，如果t代表int，ArrayOf（5，t）代表[5]int。
// 
// 如果结果类型大于可用地址空间，则
// ArrayOf panics。
func ArrayOf(length int, elem Type) Type {
	if length < 0 {
		panic("reflect: negative length passed to ArrayOf")
	}

	typ := elem.(*rtype)

	// 在缓存中查找。
	ckey := cacheKey{Array, typ, nil, uintptr(length)}
	if array, ok := lookupCache.Load(ckey); ok {
		return array.(Type)
	}

	// 查看已知类型。
	s := "[" + strconv.Itoa(length) + "]" + typ.String()
	for _, tt := range typesByString(s) {
		array := (*arrayType)(unsafe.Pointer(tt))
		if array.elem == typ {
			ti, _ := lookupCache.LoadOrStore(ckey, tt)
			return ti.(Type)
		}
	}

	// 创建一个数组类型。
	var iarray any = [1]unsafe.Pointer{}
	prototype := *(**arrayType)(unsafe.Pointer(&iarray))
	array := *prototype
	array.tflag = typ.tflag & tflagRegularMemory
	array.str = resolveReflectName(newName(s, "", false))
	array.hash = fnv1(typ.hash, '[')
	for n := uint32(length); n > 0; n >>= 8 {
		array.hash = fnv1(array.hash, byte(n))
	}
	array.hash = fnv1(array.hash, ']')
	array.elem = typ
	array.ptrToThis = 0
	if typ.size > 0 {
		max := ^uintptr(0) / typ.size
		if uintptr(length) > max {
			panic("reflect.ArrayOf: array size would exceed virtual address space")
		}
	}
	array.size = typ.size * uintptr(length)
	if length > 0 && typ.ptrdata != 0 {
		array.ptrdata = typ.size*uintptr(length-1) + typ.ptrdata
	}
	array.align = typ.align
	array.fieldAlign = typ.fieldAlign
	array.len = uintptr(length)
	array.slice = SliceOf(elem).(*rtype)

	switch {
	case typ.ptrdata == 0 || array.size == 0:
		// 没有指针。
		array.gcdata = nil
		array.ptrdata = 0

	case length == 1:
		// 在内存中，1元素数组看起来就像元素。
		array.kind |= typ.kind & kindGCProg
		array.gcdata = typ.gcdata
		array.ptrdata = typ.ptrdata

	case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*goarch.PtrSize:
		// 元素很小，带有指针掩码；阵列仍然很小。
		// 通过将elem 
		// 中的每个1位转换为较大掩码中的长度1位来创建直接指针掩码。
		mask := make([]byte, (array.ptrdata/goarch.PtrSize+7)/8)
		emitGCMask(mask, 0, typ, array.len)
		array.gcdata = &mask[0]

	default:
		// 创建一个程序，该程序发出一个元素
		// 然后重复生成数组。
		prog := []byte{0, 0, 0, 0} // 将是prog 
		prog = appendGCProg(prog, typ)
		// 从ptrdata到大小的焊盘长度。
		elemPtrs := typ.ptrdata / goarch.PtrSize
		elemWords := typ.size / goarch.PtrSize
		if elemPtrs < elemWords {
			// 发出文字0位，然后根据需要重复。
			prog = append(prog, 0x01, 0x00)
			if elemPtrs+1 < elemWords {
				prog = append(prog, 0x81)
				prog = appendVarint(prog, elemWords-elemPtrs-1)
			}
		}
		// 重复长度-1次。
		if elemWords < 0x80 {
			prog = append(prog, byte(elemWords|0x80))
		} else {
			prog = append(prog, 0x80)
			prog = appendVarint(prog, elemWords)
		}
		prog = appendVarint(prog, uintptr(length)-1)
		prog = append(prog, 0)
		*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
		array.kind |= kindGCProg
		array.gcdata = &prog[0]
		array.ptrdata = array.size // 高估但正常；必须匹配程序
	}

	etyp := typ.common()
	esize := etyp.Size()

	array.equal = nil
	if eequal := etyp.equal; eequal != nil {
		array.equal = func(p, q unsafe.Pointer) bool {
			for i := 0; i < length; i++ {
				pi := arrayAt(p, i, esize, "i < length")
				qi := arrayAt(q, i, esize, "i < length")
				if !eequal(pi, qi) {
					return false
				}

			}
			return true
		}
	}

	switch {
	case length == 1 && !ifaceIndir(typ):
		// 1个direct iface类型的数组可以是direct 
		array.kind |= kindDirectIface
	default:
		array.kind &^= kindDirectIface
	}

	ti, _ := lookupCache.LoadOrStore(ckey, &array.rtype)
	return ti.(Type)
}

func appendVarint(x []byte, v uintptr) []byte {
	for ; v >= 0x80; v >>= 7 {
		x = append(x, byte(v|0x80))
	}
	x = append(x, byte(v))
	return x
}

// toType从*rtype转换为可以返回
// 到package reflect客户端的类型。在gc中，唯一需要考虑的是
// 必须用nil类型替换nil*rtype，但在gccgo中，这个
// 函数负责确保同一
// 类型的多个*rtype合并为一个类型。
func toType(t *rtype) Type {
	if t == nil {
		return nil
	}
	return t
}

type layoutKey struct {
	ftyp *funcType // 函数签名
	rcvr *rtype    // 接收器类型，如果没有，则为零
}

type layoutType struct {
	t         *rtype
	framePool *sync.Pool
	abi       abiDesc
}

var layoutCache sync.Map // 映射[layoutKey]布局类型

// funcLayout计算表示
// 堆栈分配的函数参数和函数
// 类型t.
// 如果rcvr！=无，rcvr指定接收器的类型。
// 返回的类型只存在于GC中，所以我们只填写GC相关信息。
// 目前，这只是大小和GC程序。我们还填写了
// 名称以供可能的调试使用。
func funcLayout(t *funcType, rcvr *rtype) (frametype *rtype, framePool *sync.Pool, abi abiDesc) {
	if t.Kind() != Func {
		panic("reflect: funcLayout of non-func type " + t.String())
	}
	if rcvr != nil && rcvr.Kind() == Interface {
		panic("reflect: funcLayout with interface receiver " + rcvr.String())
	}
	k := layoutKey{t, rcvr}
	if lti, ok := layoutCache.Load(k); ok {
		lt := lti.(layoutType)
		return lt.t, lt.framePool, lt.abi
	}

	// 计算ABI布局。
	abi = newAbiDesc(t, rcvr)

	// 构建包含gc程序的虚拟rtype 
	x := &rtype{
		align: goarch.PtrSize,
		// 不要在此处添加溢出空间；只在
		// reflectcall的帧中需要，在分配的帧中不需要。
		// TODO（mknyszek）：当不再需要在框架中注册
		// 溢出空间时，删除此注释。
		size:    align(abi.retOffset+abi.ret.stackBytes, goarch.PtrSize),
		ptrdata: uintptr(abi.stackPtrs.n) * goarch.PtrSize,
	}
	if abi.stackPtrs.n > 0 {
		x.gcdata = &abi.stackPtrs.data[0]
	}

	var s string
	if rcvr != nil {
		s = "methodargs(" + rcvr.String() + ")(" + t.String() + ")"
	} else {
		s = "funcargs(" + t.String() + ")"
	}
	x.str = resolveReflectName(newName(s, "", false))

	// 未来调用方的缓存结果
	framePool = &sync.Pool{New: func() any {
		return unsafe_New(x)
	}}
	lti, _ := layoutCache.LoadOrStore(k, layoutType{
		t:         x,
		framePool: framePool,
		abi:       abi,
	})
	lt := lti.(layoutType)
	return lt.t, lt.framePool, lt.abi
}

// ifaceIndir报告t是否间接存储在接口值中。
func ifaceIndir(t *rtype) bool {
	return t.kind&kindDirectIface == 0
}

// 注意：此类型必须与运行时一致。位向量。
type bitVector struct {
	n    uint32 // 位数
	data []byte
}

// 在位图中追加一位。
func (bv *bitVector) append(bit uint8) {
	if bv.n%8 == 0 {
		bv.data = append(bv.data, 0)
	}
	bv.data[bv.n/8] |= bit << (bv.n % 8)
	bv.n++
}

func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
	if t.ptrdata == 0 {
		return
	}

	switch Kind(t.kind & kindMask) {
	case Chan, Func, Map, Pointer, Slice, String, UnsafePointer:
		// 1个指针位于表示的开头
		for bv.n < uint32(offset/uintptr(goarch.PtrSize)) {
			bv.append(0)
		}
		bv.append(1)

	case Interface:
		// 2个指针
		for bv.n < uint32(offset/uintptr(goarch.PtrSize)) {
			bv.append(0)
		}
		bv.append(1)
		bv.append(1)

	case Array:
		// 重复内部类型
		tt := (*arrayType)(unsafe.Pointer(t))
		for i := 0; i < int(tt.len); i++ {
			addTypeBits(bv, offset+uintptr(i)*tt.elem.size, tt.elem)
		}

	case Struct:
		// 应用字段
		tt := (*structType)(unsafe.Pointer(t))
		for i := range tt.fields {
			f := &tt.fields[i]
			addTypeBits(bv, offset+f.offset(), f.typ)
		}
	}
}
